# include "allocation.h"

static ArrayList **allocNodes;
static char **mapUCEs;
static ArrayList *notAllocated;
static Graph *allocGraph;
static int nUCEs;
static int noLimits;
static int calc = 0;
static int nStudentsCalc = 0;

static Graph * clearGraph ();
static void inicializaAllocation();
static int getIndiceUCE (char *uceName);
static int getIndiceList (LinkedList *lst, int uce);
static int canAddStudent (int uce);
static int maxStudents (int uce);
static int studentsAssigned (int uce);
static int canAddStudent2 (int uce1, int uce2);
static int adicionaStudent (Student *st, int uce);
static int adicionaStudent2 (Student *st, int uce1, int uce2);
static int comparaEstudantes (void *a, void *b);
static int ordenaUCE (int uce);
static int setNotAllocated (Student *st);
static int removeStudent (Student *st, int uce);
static int uceHasStudent (Student *st, int uce);
static int assignStudent (Student *st, int uce);
static int assignStudent2 (Student *st, int uce1, int uce2);
static char * getMyUCE (LinkedList *l, int myUCE);
static int cutEdge (int uce1, int uce2);
static int distribuicaoInicial ();
static int memmoryAllocation ();
static int addStudent (Student *st);
static int addExtra (Student *st);
static int compSelections (void *a,void *b);
static int takeStudent (int uce);
static int takeExceedStudents (int uce);
static int distribuicaoFinal ();
static int executa();
static void validaMax (Graph *g, int *res, int *n);

static int passaM (Graph *g, int *res, int cor, int max) {
	int i,count = 0;
	if (!g) return 0;
	if (!res) return 0;
	for (i=0;i<g->nodes;i++) if (res[i] == cor) count++;
	if (count > max) return 1;
	else return 0;
}
static int buscaIndex (Graph *g, int *res, int cor, int off) {
	int i;
	for (i=off+1;i<g->nodes;i++) if (res[i] == cor) return i;
	return -1;
}
static void acrescentarUmaCor (Graph *g, int *res, int cor, int *n) {
	int k = buscaIndex(g,res,cor,-1);
	res[k] = (*n);
	(*n)++;
}
static int temAdjacenteIgual (Graph *g, int *res, int cor, int ind) {
	int adj[g->nodes];
	int n;
	n = adjacentList(g,ind,adj);
	int i;
	for (i=0;i<n;i++) {
		if (res[adj[i]] == cor) return 1;
	}
	return 0;
}
static int tentarUsarCorExistente (Graph *g, int *res, int cor, int *n, int max) {
	int i,j=-1,conseguiu=0;
	j = buscaIndex(g,res,cor,j);
	while (j!=-1&&!conseguiu) {
		for (i=0;i<g->nodes&&!conseguiu;i++) {
			if (i!=j) {
				if (!adjacent(g,i,j)&&res[i]!=res[j]&&!temAdjacenteIgual(g,res,res[i],j)) {
					if (!passaM(g,res,res[i],max-1)) {
						res[j] = res[i]; conseguiu = 1;
					}
				}
			}
		}
		j = buscaIndex(g,res,cor,j);
	}
	if (conseguiu) return 1;
	else return 0;
}
static void alteraEssaCor (Graph *g, int *res, int cor, int *n,int max) {
	// tentar usar outra cor!
	if (!tentarUsarCorExistente(g,res,cor,n,max)) acrescentarUmaCor(g,res,cor,n);
}
static void validaMax (Graph *g, int *res, int *n) {
	int i,c = 1;
	int cfg = 0; int na = *n;
	char *value = getConfigurationValue(CONFIG_LABORATORIOS);
	if (value) cfg = atoi(value);
	if (noLimits) cfg = 0;
	if (cfg) {
		while (c < na+1) {
			while (passaM(g,res,c,cfg)) {
				alteraEssaCor(g,res,c,n,cfg);
			}
			c++;
		}
	}
}

static LinkedList *bestColoring;
static int *nColors;
static int **colors;
static int totalMaxColors;

static int executa () {
	Graph *m,*g; LinkedList *aux1,*aux,*lst;
	int ind,k,i,j,n,stop = 0; Graph *tmp;
	inicializaAllocation();
	distribuicaoInicial();
	g = clearGraph();
	int p,probCount = 0,min,max,iA,iB,c;
	int cfg = 0;
        char *str = getConfigurationValue(CONFIG_HORARIOS);
        if (str) cfg = atoi(str);
	if (noLimits) cfg = 0;
	int res[nUCEs];
	if (!g) return 0;
	while (!stop) {
		ind = 0;
                probCount++; if (probCount > PROB_MAX) return 0;
                bestColoring = aux = getConnectedSubGraphs(g);
		if (!aux) return 0;
		p = listSize(bestColoring);
		nColors = (int *) malloc(sizeof(int)*p);
		colors = (int **) malloc(sizeof(int *)*p);
                m = getData(aux);
                max = colorGraph(m,res);
		validaMax(m,res,&max);
		nColors[ind] = max;
		colors[ind] = (int *) malloc(sizeof(int)*m->nodes);
		for (k=0;k<m->nodes;k++) colors[ind][k] = res[k];
		ind++;
                aux = aux->next;
                while (aux) {
                        tmp = getData(aux);
                        n = colorGraph(tmp,res);
			validaMax(tmp,res,&n);
			nColors[ind] = n;
			colors[ind] = (int *) malloc(sizeof(int)*tmp->nodes);
			for (k=0;k<tmp->nodes;k++) colors[ind][k] = res[k];
			ind++;
                        if (n>max) max = n;
                        aux = aux->next;
                        if (n==max) m = tmp;
                }
                freeGraph(g);
                if (cfg) {
                        if (max>cfg) {
				free(nColors);
				aux = bestColoring;
				ind = 0;
				while (aux) {
					aux1 = aux;
					tmp = getData(aux);
					free(colors[ind++]);
					aux = aux->next;
					free(aux1);
				}
				free(colors);
				freeLinkedList(bestColoring);
                                min = -1;
                                for (i=0;i<m->nodes;i++) {
                                        for (j=0;j<m->nodes;j++) {
                                                c = getEdgeValue(m,i,j);
                                                if (i!=j) {
                                                        if ((c && c < min) || c == -1) {
                                                                iA = m->label[i];
                                                                iB = m->label[j];
                                                                min = c;
                                                        }
                                                }
                                        }
                                }
                                if (min == -1) return 0;
                                cutEdge(iA,iB);
                        } else stop = 1;
                } else stop = 1;
	}
	for (i=0;i<nUCEs;i++) {
		takeExceedStudents(i);
	}
	distribuicaoFinal();
	return 1;
}
static int distribuicaoFinal () {
	ArrayList *alunos;
        int i,n; Student *aux;
        alunos = getStudentsList();
        n = arrayGetLength(alunos);
	nStudentsCalc = n;
        for (i=0;i<n;i++) {
                aux = arrayGet(alunos,i);
                if (aux && aux->type == EXTRA) {
                        addExtra(aux);
                }
        }
        return 1;
}
static int maxStudents (int uce) {
	ChainingHashMap *map; char *str = NULL;
        UCE *aux;
        map = getUCEsMap();
        if (!map) return 0;
        str = mapUCEs[uce];
        if (!str) return 0;
        aux = getChaining(map,str);
        if (!aux) return 0;
	return aux->maxStudents;
}
static int takeExceedStudents (int uce) {
	int n,m;
	m = maxStudents(uce);
	n = studentsAssigned(uce);
	while (n > m) {
		takeStudent(uce);
		n--;
	}
}
static int takeStudent (int uce) {
	Student *st; ArrayList *lst;
	int n;
	if (!allocNodes) return 0;
	lst = allocNodes[uce];
	if (!lst) return 0;
	n = studentsAssigned(uce);
	st = arrayGet(lst,n-1);
	arrayRemoveFrom(lst,n-1);
	if (!assignStudent(st,uce)) return 0;
	return 1;
}
static int compSelections (void *a, void *b) {
        Selection *a1 = a;
        Selection *b1 = b;
        if (a1->preference > b1->preference) return 1;
        else if (a1->preference < b1->preference) return (-1);
        else return 0;
}
static int addStudent (Student *st) {
	int i,f;
	LinkedList *lst;
	Selection *sel,*s1,*s2;
	for (i=0;i<nUCEs;i++) {
		f = 0;
		lst = st->selections;
		while (lst&&!f) {
			sel = getData(lst);
			if (sel->uceName && mapUCEs[i]) if (!strcmp(sel->uceName,mapUCEs[i])) f = 1;
			lst = lst->next;	
		}
		if (!f) st->selections = insertElemHead(st->selections,newSelection(strdup(mapUCEs[i]),0));
	}
	st->selections = sortList(st->selections,compSelections,1);
	if (st->ucesWanted == 1) {
		s1 = getData(st->selections);
		adicionaStudent(st,getIndiceUCE(s1->uceName));
	}
	else {
		s1 = getData(st->selections);
		s2 = getData(st->selections->next);
		adicionaStudent2(st,getIndiceUCE(s2->uceName),getIndiceUCE(s1->uceName));
	}
}
static int addExtra (Student *st) {
        int i,f;
        LinkedList *lst;
        Selection *sel,*s1,*s2;
        for (i=0;i<nUCEs;i++) {
                f = 0;
                lst = st->selections;
                while (lst&&!f) {
                        sel = getData(lst);
                        if (sel->uceName && mapUCEs[i]) if (!strcmp(sel->uceName,mapUCEs[i])) f = 1;
                        lst = lst->next;
                }
                if (!f) st->selections = insertElemHead(st->selections,newSelection(strdup(mapUCEs[i]),0));
        }
        st->selections = sortList(st->selections,compSelections,1);
        if (st->ucesWanted == 1) {
                s1 = getData(st->selections);
                assignStudent(st,getIndiceUCE(s1->uceName));
        }
        else {
                s1 = getData(st->selections);
                s2 = getData(st->selections->next);
                assignStudent2(st,getIndiceUCE(s2->uceName),getIndiceUCE(s1->uceName));
        }
}
static int memmoryAllocation () {
	ChainingHashMap *map;
	LinkedList *aux,*lst;
	char *str;
	map = getUCEsMap();
	int i,n = 0;
	if (map) {
		aux = lst = keySetChaining(map);
		if (aux) {
			while (aux) {
				aux = aux->next; n++;
			}
			allocNodes = (ArrayList **) malloc(sizeof(ArrayList *)*n);
			mapUCEs = (char **) malloc(sizeof(char*)*n);
			for (i=0;i<n;i++) {
				allocNodes[i] = NULL;
				mapUCEs[i] = NULL;
			}
			nUCEs = n;
			allocGraph = newGraph(n);
			aux = lst;
			for (i=0;aux;i++) {
				str = getData(aux);
				mapUCEs[i] = strdup(str);
				aux = aux->next;
			}
			freeLinkedList(lst);
			return 1;
		}
	}
	return 0;
}
static int distribuicaoInicial () {
	ArrayList *alunos;
	int i,n; Student *aux;
	if (!memmoryAllocation()) return 0;
	alunos = getStudentsList();
	n = arrayGetLength(alunos);
	for (i=0;i<n;i++) {
		aux = arrayGet(alunos,i);
		if (aux && aux->type != EXTRA) {
			addStudent(aux);
		}
	}
	for (i=0;i<nUCEs;i++) ordenaUCE(i);
	return 1;
}
static int cutEdge (int uce1, int uce2) {
	ArrayList *u1, *u2;
	int i,j,n,m,f;
	Student *s1,*s2;
	if (!allocNodes) return 0;
	if (!allocGraph) return 0;
	setEdgeValue(allocGraph,uce1,uce2,-1);
	u1 = allocNodes[uce1]; u2 = allocNodes[uce2];
	if (!u1) return 0; if (!u2) return 0;
	n = arrayGetLength(u1); m = arrayGetLength(u2);
	for (i=0;i<n;i++) {
		f = 0;
		s1 = arrayGet(u1,i);
		if (!s1) continue;
		for (j=0;j<m&&!f;j++) {
			s2 = arrayGet(u2,j);
			if (!s2) continue;
			if (s1->number == s2->number) {
				f = 1; // tirar e realocar!
				arrayRemoveFrom(u1,i);
				arrayRemoveFrom(u2,j);
				n--;
				m--;
				assignStudent2(s1,uce1,uce2);
				i--;
			}
		}
	}
	ordenaUCE(uce1); ordenaUCE(uce2);
	return 1;
}
static char * getMyUCE (LinkedList *l, int myUCE) {
	int i; LinkedList *aux = l;
	Selection *sel;
	for (i=0;i<myUCE&&aux;i++) aux = aux->next;
	if (aux) {
		sel = getData(aux);
		return sel->uceName;
	}
	return NULL;
}
static int assignStudent2 (Student *st, int uce1, int uce2) {
	LinkedList *lst;
	int i1,i2;
	int i,j,myUCE1,myUCE2,add = 0;
	lst = st->selections;
	char *testeA, *testeB;
	myUCE1 = getIndiceList(lst,uce1);
	myUCE2 = getIndiceList(lst,uce2);
	if (myUCE1 > myUCE2) return assignStudent2(st,uce2,uce1);
	for (i=myUCE1;i<nUCEs-1 && !add;i++) {
		testeA = getMyUCE(lst,i);
		for (j=i+1;j<nUCEs && !add;j++) {
			testeB = getMyUCE(lst,j);
			i1 = getIndiceUCE(testeA);
			i2 = getIndiceUCE(testeB);
			if (canAddStudent2(i1,i2)) {
				adicionaStudent2(st,i1,i2);
				ordenaUCE(i1); ordenaUCE(i2);
				add = 1;
			}
		}
	}
        if (!add) setNotAllocated(st);
	return 1;
}
static int stCompare (void *a, void *b) {
	Student *s1,*s2;
	s1 = a;
	s2 = b;
	if (s1->number == s2->number) return 1;
	else return 0;
}
static int assignStudent (Student *st, int uce) {
        int iA,iB,n,i,add = 0,idA,idB;
        Selection *sel; ArrayList *lst;
        LinkedList *l = st->selections;
	iA = getIndiceList(st->selections,uce);
	n = listSize(l);
	if (uce < 0 || uce > nUCEs-1) {
		setNotAllocated(st); //printf("ERRO\n");
		return 1;
	}
        if (st->ucesWanted > 1) {
                for (i=0;i<nUCEs;i++) { if (i!=iA) { if (uceHasStudent(st,i)) break; } }
                if (i!=nUCEs) { 
			if (!allocNodes) return 0;
			lst = allocNodes[i];
			iB = getIndiceList(st->selections,i);
			arrayRemove(lst,st,stCompare);
                	iA++;
		} else {
			iB = iA + 1;
			if (iB == iA) iA++;
			if (iB > nUCEs || iA > nUCEs ) { return 0; }
		}
		idA = getIndiceUCE(getMyUCE(st->selections,iA));
		idB = getIndiceUCE(getMyUCE(st->selections,iB));
                assignStudent2(st,idB,idA);
        } else {
                for (i=0;i<=iA&&l;i++) l = l->next;
                while (l&&!add) {
                        sel = getData(l);
			idA = getIndiceUCE(getMyUCE(st->selections,i));
                        if (canAddStudent(idA)) {
                                adicionaStudent(st,idA);
                                add = 1;
                        }
			i++;
                        l = l->next;
                }
                if (!add) setNotAllocated(st);
        }
	return 1;
}
static int getIndiceList (LinkedList *lst, int uce) {
	if (!mapUCEs) return -1;
	if (uce < 0 || uce > nUCEs - 1) return -1;
	char *str = mapUCEs[uce];
	LinkedList *aux = lst; Selection *sel;
	int i = 0;
	while (aux) {
		sel = getData(aux);
		if (sel->uceName && str) if (!strcmp(sel->uceName,str)) return i;
		i++;
		aux = aux->next;
	}
	return -1;
}
static int uceHasStudent (Student *st, int uce) {
	if (!allocNodes) return 0;
        if (uce > nUCEs - 1) return 0;
	ArrayList *lst = allocNodes[uce];
	int i,n; Student *aux;
        if (lst) {
                n = arrayGetLength(lst);
                for (i=0;i<n;i++) {
                        aux = arrayGet(lst,i);
			if (!aux) continue;
                        if (aux->number == st->number) return 1;
		}
        }
	return 0;
}
static int adicionaStudent2 (Student *st, int uce1, int uce2) {
	if (!allocGraph) return 0;
	if (!adicionaStudent(st,uce1)) return 0;
	if (!adicionaStudent(st,uce2)) return 0;
	int c = getEdgeValue(allocGraph,uce1,uce2);
	setEdgeValue(allocGraph,uce1,uce2,c+1);	
}
static int removeStudent (Student *st, int uce) {
	if (!allocNodes) return 0;
	if (uce > nUCEs - 1) return 0;
        ArrayList *lst = allocNodes[uce];
	int i,n,f = 0; Student *aux;
	if (lst) {
		n = arrayGetLength(lst);
		for (i=0;i<n&&!f;i++) {
			aux = arrayGet(lst,i);
			if (!aux) continue;
			if (aux->number == st->number) f = 1;
		}
		if (f) {
			i--;
			arrayRemoveFrom(lst,i);
		}
	}
}
static int setNotAllocated (Student *st) {
	if (!notAllocated) notAllocated = newArrayList(STUDENT_LIST_SIZE);
	arrayInsert(notAllocated,st);
	return 1;
}
static void printa (ArrayList *lst) {
	int i,n = arrayGetLength(lst);
	Student *st;
	for (i=0;i<n;i++) {
		st = arrayGet(lst,i);
		printf("%d - %d (%d)\n",i,st->number,st->average);
	}
}
static int ordenaUCE (int uce) {
	if (!allocNodes) return 0;
        if (uce > nUCEs - 1) return 0;
	ArrayList *lst = allocNodes[uce];
	if (lst) {
		arraySort(lst,comparaEstudantes,1);
		//printa(lst);
	}
	return 1;
}
static int comparaEstudantes (void *a, void *b) {
	Student *s1 = a;
	Student *s2 = b;
	return compareStudent(s1,s2);
}
static int adicionaStudent (Student *st, int uce) {
	if (!allocNodes) return 0;
	if (uce > nUCEs - 1) return 0;
	if (uce < 0) return 0;
	ArrayList *lst = allocNodes[uce];
	if (!lst) lst = allocNodes[uce] = newArrayList(STUDENT_LIST_SIZE);
	arrayInsert(lst,st);
}
static int canAddStudent2 (int uce1,  int uce2) {
	if (!canAddStudent(uce1)) return 0;
	if (!canAddStudent(uce2)) return 0;
	if (!allocGraph) return 0;
	if (allocGraph->nodes < nUCEs) return 0;
	int c = getEdgeValue(allocGraph,uce1,uce2);
	if (c == -1) { return 0; }
	else return 1;
}
static int getIndiceUCE (char *uce) {
	int i = 0;
	int n; char *name;
	if (!mapUCEs) return -1;
	else {
		for (i=0;i<nUCEs;i++) {
			name = mapUCEs[i];
			if (uce && name) if (!strcmp(uce,name)) { return i; }
		}
	}
	return -1;
}
static int canAddStudent (int uce) {
	ChainingHashMap *map; char *str = NULL;
	UCE *aux;
	if (noLimits) return 1;
	map = getUCEsMap();
	if (!map) return 0;
	str = mapUCEs[uce];
	if (!str) return 0;
	aux = getChaining(map,str);
	if (!aux) return 0;
	if (aux->maxStudents && ((aux->maxStudents) < studentsAssigned(uce)+1)) return 0;
	else return 1;
}
static int studentsAssigned (int uce) {
	if (!allocNodes) return 0;
	if (nUCEs-1 < uce) return 0;
	ArrayList *lst = allocNodes[uce];
	if (!lst) return 0;
	return arrayGetLength(lst);
}
static void inicializaAllocation () {
	allocNodes = NULL;
	mapUCEs = NULL;
	allocGraph = NULL;
	nUCEs = 0;
}
static Graph * clearGraph () {
        if (!allocGraph) return NULL;
        Graph *g = newGraph(allocGraph->nodes);
        int i,j,c;
        for (i=0;i<g->nodes;i++) {
                for (j=0;j<g->nodes;j++) {
                        c = getEdgeValue(allocGraph,i,j);
                        if (c == -1) setEdgeValue(g,i,j,0);
                        else setEdgeValue(g,i,j,c);
                }
        }
        return g;
}

static void validaResultDir () {
        int i,n = strlen(RESULT_DIR) + 4;
        char *path = (char *) malloc(sizeof(char)*n);
        sprintf(path,"%s",RESULT_DIR);
        FILE *fp;
        fp = fopen(path,"r");
        if (fp) fclose(fp);
        else mkdir(path,S_IRWXU | S_IRWXG | S_IRWXO);
        free(path);

}
static void validaResultProjectDir () {
        validaResultDir();
        char *name = getProjectName();
        int i,n = strlen(RESULT_DIR) + strlen(name) + 4;
        char *path = (char *) malloc(sizeof(char)*n);
        sprintf(path,"%s/%s",RESULT_DIR,name);
        FILE *fp;
        fp = fopen(path,"r");
        if (fp) fclose(fp);
        else mkdir(path,S_IRWXU | S_IRWXG | S_IRWXO);
        free(path);
}
static int writeInfo (int colorss[]) {
        char *name = getProjectName();
	if (!mapUCEs) return 0;
        int i,n = strlen(RESULT_DIR) + strlen(name) + 20;
        char *path = (char *) malloc(sizeof(char)*n);
        sprintf(path,"%s/%s/horario",RESULT_DIR,name);
        FILE *fp = fopen(path,"w");
        char *s;
        if (fp) {
                fprintf(fp,"Horários Necessários: %d\n",totalMaxColors);
                for (i=0;i<nUCEs;i++) {
                        s = mapUCEs[i];
                        fprintf(fp,"%s (Horário %d)\n",s,colorss[i]);
                }
                fclose(fp);
        }
        free(path);
	return 1;
}
static int writeStudentsNotAllocated () {
        char *name = getProjectName();
        if (!mapUCEs) return 0;
        int i,j,n; Student *st;
        char *uce;ArrayList *lst;
        char *path; FILE *fp;
        path = (char *) malloc(sizeof(char)*100);
        sprintf(path,"%s/%s/non.allocated",RESULT_DIR,name);
        lst = notAllocated;
        fp = fopen(path,"w");
        if (fp) {
             n = arrayGetLength(lst);
            for (j=0;j<n;j++) {
                    st = arrayGet(lst,j);
			if (!st) continue;
                    fprintf(fp,"%s (%d)\n",st->name,st->number);
             }
             fclose(fp);
         }
        free(path);
        return 1;
}
static int writeStudentsA (Graph *tmp) {
        char *name = getProjectName();
	if (!mapUCEs) return 0;
        int i,j,n; Student *st;
        char *uce;ArrayList *lst;
        char *path; FILE *fp;
        for (i=0;i<tmp->nodes;i++) {
                uce = mapUCEs[tmp->label[i]];
                n = strlen(RESULT_DIR) + strlen(name) + 6 + strlen(uce);
                path = (char *) malloc(sizeof(char)*n);
                sprintf(path,"%s/%s/%s",RESULT_DIR,name,uce);
                lst = allocNodes[tmp->label[i]];
                fp = fopen(path,"w");
                if (fp) {
                        n = arrayGetLength(lst);
                        for (j=0;j<n;j++) {
                                st = arrayGet(lst,j);
				if (!st) continue;
                                fprintf(fp,"%s (%d)\n",st->name,st->number);
                        }
                        fclose(fp);
                }
                free(path);
        }
	return 1;
}
static int passaMaxPintar (Graph *g, int *cores, int corDaqui, int nodosPintados, int max) {
	int i,s=0;
	for (i=0;i<g->nodes;i++) {
		if (cores[i] == corDaqui) s++;
	}
	if (s == 0) return 1;
	else {
		if (!max) return 0;
		if (nodosPintados+s > max) return 1;
		else return 0;
	}
}
static void colora (Graph *g, int nivel, int cor, int *nodosPintados, int *nodosPintadosCor, int max, int *res) {
	int *coresNivel = colors[nivel];
	int n = nColors[nivel];
	int j,i,pintou = 0;
	for (i=1;i<n+1&&!pintou;i++) {
		if (!passaMaxPintar(g,coresNivel,i,*nodosPintadosCor,max)) {
			for (j=0;j<g->nodes;j++) {
				if (coresNivel[j] == i) {
					coresNivel[j] = cor;
					res[g->label[j]] = cor;
					(*nodosPintados)++;
					(*nodosPintadosCor)++;
				}
			}
			pintou = 1;
		}
	}
}
static int * daHorario () {
	if (!executa()) return NULL;
	// agora ja tenho o resultado! é só mandar bir!
	Graph *g;
	int s = 0;
	int cfg = 0;
        char *value = getConfigurationValue(CONFIG_LABORATORIOS);
        if (value) cfg = atoi(value);
	if (noLimits) cfg = 0;
	totalMaxColors = 0;
	int *res = NULL;
	LinkedList *lst = bestColoring;
	while (lst) {
		g = getData(lst);
		s+=g->nodes;
		lst = lst->next;
	}
	res = (int *) malloc(sizeof(int)*s);
	int c,i=0,ind,j;
	for (c=-1;i<s;c--) {
		lst = bestColoring; j = 0; ind = 0;
		while (lst&&i<s) {
			if (cfg && j < cfg) break; 
			colora(getData(lst),ind,c,&i,&j,cfg,res);
			lst = lst->next; ind++;
		}
	}
	c++;
	c = (-1)*c;
	totalMaxColors = c;
	for (i=0;i<s;i++) res[i] = (-1)*res[i];
	return res;
}
CommandResult * command_executa (int argc, char *argv[]) {
	if (!hasProject()) {
                printf("É necessário ter um projecto carregado\n");
                return successCommandResult();
        }
	calc = 1;
	noLimits = 0;
        LinkedList *aux,*lst;
        Graph *tmp; int *res;
        int n,dir = 1,i;
	res = daHorario();
	if (!res) {
		printf("Não é possivel realizar o processamento, verifique os dados\n");
		return successCommandResult();
	}
	aux = lst = bestColoring; i=0;
	validaResultProjectDir();
	writeInfo(res);
	while (aux) {
		tmp = getData(aux);
              	writeStudentsA(tmp);
		writeStudentsNotAllocated();
               	freeGraph(tmp);
               	aux = aux->next;
        }
	writeStudentsNotAllocated();
        freeLinkedList(lst);
        printf("Resultados calculados e escritos no devido local\n");
        return successCommandResult();
}
CommandResult * command_executaNoLimits (int argc, char *argv[]) {
        if (!hasProject()) {
                printf("É necessário ter um projecto carregado\n");
                return successCommandResult();
        }
	calc = 0;
        noLimits = 1;
        LinkedList *aux,*lst;
        Graph *tmp; int *res;
        int n,dir = 1,i;
        res = daHorario();
        if (!res) {
                printf("Não é possivel realizar o processamento, verifique os dados\n");
                return successCommandResult();
        }
        aux = lst = bestColoring; i=0;
	validaResultProjectDir();
        while (aux) {
                tmp = getData(aux);
                freeGraph(tmp);
                aux = aux->next;
        }
        freeLinkedList(lst);
        printf("Número minimo de horários por forma a ninguem ser contrariado: %d\n",totalMaxColors);
        return successCommandResult();
}
static int calcVagas () {
	ChainingHashMap *map = getUCEsMap();
	UCE *uce;
	int vagas = 0;
	if (!map) return 0;
        LinkedList *aux,*lst = keySetChaining(map);
        if (!lst) return 0;
        aux = lst;
        while (lst) {
                uce = getData(lst);
		if (uce->maxStudents > 0) vagas += uce->maxStudents;
                lst = lst->next;
        }
        freeLinkedList(aux);
	return vagas;
}
static int vagasUCE (int i) {
	ChainingHashMap *map = getUCEsMap();
        UCE *uce;
        int vagas = 0;
        if (!map) return 0;
        uce = getChaining(map,mapUCEs[i]);
	return uce->maxStudents;

}
static int isPref (Student *st, int uce) {
	LinkedList *lst = st->selections;
	int is = 0;
	int max = 0; Selection *sel;
	int uc = -1,s = 0;
	while (lst) {
		sel = getData(lst);
		if (sel->preference > max) {
			uc = s;
			max = sel->preference;
			if (!strcmp(sel->uceName,mapUCEs[uce])) is = 1;
			if (is) is = 0;
		} else if (sel->preference == max) {
			if (!strcmp(sel->uceName,mapUCEs[uce])) is = 1;
		}
		lst = lst->next;
		s++;
	}
	return is;
}
static int alunosUCEPref (int uce) {
	ArrayList *lst = allocNodes[uce];
	int n = 0;
	if (lst) n = arrayGetLength(lst);
	int i; Student *st;
	int c = 0;
	for (i=0;i<n;i++) {
		st = arrayGet(lst,i);
		if (!st) continue;
		if (isPref(st,uce)) c++;
	}
	return c;
}
static int alunosUCENPref (int uce) {
        ArrayList *lst = allocNodes[uce];
        int n = 0;
        if (lst) n = arrayGetLength(lst);
        int i; Student *st;
        int c = 0;
        for (i=0;i<n;i++) {
                st = arrayGet(lst,i);
		if (!st) continue;
                if (!isPref(st,uce)) c++;
        }
        return c;
}
static int calcInscritos () {
	int i;
	ArrayList *l;
	int ins = 0;
	for (i=0;i<nUCEs;i++) {
		l = allocNodes[i];
		if (l) ins += arrayGetLength(l);
	}
	return ins;
}
static int alunosUCE(int u) {
	ArrayList *alunos;
        int i,n; Student *aux;
        alunos = getStudentsList();
        n = arrayGetLength(alunos);
	int c=0;
        for (i=0;i<n;i++) {
                aux = arrayGet(alunos,i);
		if (!aux) continue;
		if (isPref(aux,u)) c++;
        }
        return c;
}
static void indForca () {
	int i;
	float v;
	float st,r;
	for (i=0;i<nUCEs;i++) {
		v = vagasUCE(i);
		st = alunosUCE(i);
		if (v == 0) continue;
		r = st/v;
		printf("Indice de força para a UCE %s: %f\n",mapUCEs[i],r);
	}
}
static void potencial () {
	int i;
        float v;
        float st,r;
        for (i=0;i<nUCEs;i++) {
                v = vagasUCE(i);
                st = alunosUCEPref(i);
                if (v == 0) continue;
		r = (st-v)/v;
                printf("Potencial para a UCE %s: %f\n",mapUCEs[i],r);
        }
}
static void fraqueza () {
	int i;
        float v;
        float st,r;
        for (i=0;i<nUCEs;i++) {
                v = vagasUCE(i);
                st = alunosUCENPref(i);
                if (v == 0) continue;
                r = (st-v)/v;
                printf("Indice de Fraqueza para a UCE %s: %f\n",mapUCEs[i],r);
        }
}
static int proximidade (int uceA, int uceB) {
	int n = getEdgeValue(allocGraph,uceA,uceB);
	if (n < 0) return n;
	else return 0;
}
static float taxaOcupacao () {
        int n = 0;
        int incritos = calcInscritos();
        int vagas = calcVagas();
	if (vagas == 0) return 1;
	float res = (float) incritos / (float) (vagas);
        return res;
}

CommandResult * command_taxaOcupacao (int argc, char *argv[]) {
	if (!calc) {
		printf("Ainda não foi invocada a rotina de alocação de Alunos e UCE's\n");
		return successCommandResult();
	}
	float res = taxaOcupacao();
	printf("A taxa de ocupação é: %f\n",res);
	return successCommandResult();
}
CommandResult * command_indForca (int argc, char *argv[]) {
        if (!calc) {
                printf("Ainda não foi invocada a rotina de alocação de Alunos e UCE's\n");
                return successCommandResult();
        }
        indForca();
	return successCommandResult();
}
CommandResult * command_potencial (int argc, char *argv[]) {
        if (!calc) {
                printf("Ainda não foi invocada a rotina de alocação de Alunos e UCE's\n");
                return successCommandResult();
        }
        potencial();
	return successCommandResult();
}
CommandResult * command_fraqueza (int argc, char *argv[]) {
        if (!calc) {
                printf("Ainda não foi invocada a rotina de alocação de Alunos e UCE's\n");
                return successCommandResult();
        }
        fraqueza();
	return successCommandResult();
}
CommandResult * command_proximidade (int argc, char *argv[]) {
        if (!calc) {
                printf("Ainda não foi invocada a rotina de alocação de Alunos e UCE's\n");
                return successCommandResult();
        }
	int uce1,uce2;
	if (argc < 2) printf("Argumentos: <uceA> <uceB>\n");
	else {
		uce1 = getIndiceUCE(argv[0]);
		uce2 = getIndiceUCE(argv[1]);
		if (uce1 >= 0 && uce2 >= 0) {
			printf("Proximidade: %d\n",proximidade(uce1,uce2));
		}  else printf("UCE Inexistente\n");
	}
        return successCommandResult();
}


